package main

import "fmt"

/*
怎样实现接口之间的组合？
	接口类型间的嵌入也被称为接口的组合。
	与结构体类型间的嵌入很相似，只要把一个接口类型的名称直接写到另一个接口类型的成员列表中就可以了。

	type Animal interface {
		ScientificName() string
		Category() string
	}

	type Pet interface {
		Animal
		Name() string
	}

 */

type Pet interface {
	Name() string
	Category() string
}

type Dog struct {
	name string
}

func (dog Dog) Name() string  {
	return fmt.Sprintf("The dog Name is %s ", dog.name)
}

func (dog Dog) Category() string  {
	return "dog"
}

func (dog *Dog) SetName(name string)  {
	dog.name = name
}


type Animal interface {
	ScientificName() string
	Category() string
}

/*
	接口类型SpecialPet包含了两个成员，一个是代表了另一个接口类型的Animal，一个是方法Name的定义。
	它们都被包含在SpecialPet的类型声明的花括号中，并且都各自独占一行。此时，Animal接口包含的所有方法也就成为了SpecialPet接口的方法。
 */
type SpecialPet interface {
	Animal
	Name() string
}

func main() {

	dog :=Dog{"little dog"}
	/*
		如果使用一个变量给另外一个变量赋值，那么真正赋给后者的，并不是前者持有的那个值，而是该值的一个副本。
	 */
	var pet Pet = dog

	dog.SetName("monster")

	/*
		pet变量的字段name的值依然是"little pig"
	 */
	fmt.Println("The pet is", pet)

	/*
		声明了一个*Dog类型的变量dog01，并且没有对它进行初始化。
	 */
	var dog01 *Dog
	fmt.Println("The first dog is nil. [wrap1]")
	dog02 := dog01
	fmt.Println("The second dog is nil. [wrap1]")
	/*
		把dog02的值赋给变量pet02的时候，dog02的值会先被复制
		pet02 是一个dog02值为nil的不为空的类型
		这时的pet02的动态类型就存在了，是*Dog
	 */
	var pet02 Pet = dog02
	if pet02 == nil {
		fmt.Println("The pet02 is nil. [wrap1]")
	} else {
		fmt.Println("The pet02 is not nil. [wrap1]")
		fmt.Printf("The pet02 type is %T", pet02)
	}

}
